
"""
bid_maker v0.01 

sets the bid prices

Copyright 2011 Brian Monkaba

This file is part of ga-bitbot.

	ga-bitbot is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	ga-bitbot is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with ga-bitbot.  If not, see <http://www.gnu.org/licenses/>.
""" 
 
#
#	Generates GA trade simulation reports using the gene server
#	Also calculates & submits the next buy trigger
#

__appversion__ = "0.01a"
print "Genetic Bitcoin Bid Maker v%s"%__appversion__
# connect to the xml server
#

import xmlrpclib
import json
import paths
import gene_server_config
import time


__server__ = gene_server_config.__server__
__port__ = str(gene_server_config.__port__)

#make sure the port number matches the server.
server = xmlrpclib.Server('http://' + __server__ + ":" + __port__)  

print "bid_maker: connected to",__server__,":",__port__


from load_config import *
import __main__

#the variable values below are superceded by the configuration loaded from the 
#configuration file global_config.json
#!!!!!!!! to change the values edit the json configuration file NOT the variables below !!!!!!!!
max_length = 60 * 24 * 60
enable_flash_crash_protection = True
flash_crash_protection_delay = 180
chart_zoom_periods = 3000
chart_now_periods = 200
win_loss_gate_pct = 0.80
price_format = "%.3f"
chart_type = 0
config_loaded = 0
#load config
try:
	__main__ = load_config_file_into_object('global_config.json',__main__)
except:
	print "bid_maker: error detected while loading the configuration. the application will now exit."
	import sys
	sys.exit()
else:
	if config_loaded == False:
		print "bid_maker: configuration failed to load. the application will now exit."
		import sys
		sys.exit()
	else:
		print "bid_maker: configuration loaded."



while 1:
	start_time = time.time()

	skip_sleep_delay = False #default to sleep delay mode between cycles
				#will be set to true (and skip the sleep delay) if target prices are found.

	#get the hash list of all the databases
	gdhl = json.loads(server.get_gene_def_hash_list())
	gdhl.remove('0db45d2a4141101bdfe48e3314cfbca3') #remove the undefined db
	#for each db
	for gdh in gdhl:
		time.sleep(10) #throttle the load to the client computer and the gene server.
		#register as a default client (this will allow remote dynamic configuration of the report generation)
		pid = "BID_MAKER"
		#gdh = json.loads(server.get_default_gene_def_hash())
		#load the gene def config
		gd = json.loads(server.get_gene_def(gdh))
		server.pid_register_client(pid,gdh)

		print "_" * 80
		print "bid_maker: " + time.ctime()
		print "bid_maker: finding target bid for",gdh


		#create the trade engine	
		print "bid_maker: loading the fitness function"
		ff = None
		if gd.has_key('fitness_script'):
			ff = __import__(gd['fitness_script'])
		else:
			ff = __import__('bct')
		ff = reload(ff)	#make sure we're not using a cached version of the module
		te = ff.trade_engine()
		#te.cache.disable()	#dont use cached data for reporting
		te.cache_input = False  #dont use cached data for reporting

		#apply global configs
		te.max_length = max_length
		te.enable_flash_crash_protection = enable_flash_crash_protection 
		te.flash_crash_protection_delay = flash_crash_protection_delay
		
		#load the gene def fitness config into the trade engine
		if gd.has_key('fitness_config'):
			te = load_config_into_object(gd['fitness_config'],te)
		quartile = te.initialize()				
		#select the quartile to test
		te.test_quartile(quartile)

		#get the high score gene from the gene server
		try:
			ag = json.loads(server.get(60*60*24*7,quartile,pid))
		except:
			print "bid_maker: warning: gene server error or no data available."
			#if the quartile is active set the buy to 0 to prevent old targets from remaining active
			#this is for fault protection as it should never normaly happen:
			if quartile == server.get_active_quartile():
				p = {'buy':-1.00,'bid_maker_time_stamp':time.time(),'gene_id':ag['id'],'score':0}
				server.put_target(json.dumps(p),pid)
		else:
	
			if type(ag) == type([]):
				ag = ag[0]
	

			#load the gene dictionary into the trade engine
			te = load_config_into_object({'set':ag},te)

			print "_" * 40
			print "bid_maker: quartile:",quartile, "(%.4f)"%ag['score'],"+active"
			server.put_active_quartile(quartile,pid)

			#run the trade engine
			try:
				te.run()
			except:
				print "bid_maker: gene fault"
			else:
				if len(te.positions) == 0:
					print "bid_maker: no positions, order cleared"
					p = {'buy':-1.00,'bid_maker_time_stamp':time.time(),'gene_id':ag['id'],'score':0}
					server.put_target(json.dumps(p),pid)

				# Calc the next buy trigger point
				else: 	#if len(te.positions) > 0:
					#get the target trigger price
					target = te.get_target()
					print "bid_maker: inverse MACD result (target): ",target

					if target > te.history[1]:
						target = te.history[1]

					#first check to see if the tested input triggered a buy:
					if te.positions[-1]['buy_period'] == te.period - 1:
						p = te.positions[-1]
						target = p['buy']
					else:
						print "bid_maker: last buy order was", te.period - te.positions[-1]['buy_period'],"periods ago."
						#if not try to calculate the trigger point to get the buy orders in early...
						#print "Trying to trigger with: ",target
						st = time.time()
						te.input(st,target)
						p = te.positions[-1].copy()
						if p['buy'] != target:
							#print "Order not triggered @",target
							p['buy'] = 0.00
							p['target'] = 0.00
					
					score = te.score()
					print "bid_maker: score: ",score
					#time stamp the bid and capture the gene id
					p.update({'bid_maker_time_stamp':time.time(),'gene_id':ag['id'],'score':score})

					te.chart("./report/chart.templ",gdh + '/' + ag['id'] + '.html',write_cache_only=True)

					#print "Evaluating target price"
					if ((target >= p['buy']) or (abs(target - p['buy']) < 0.01)) and p['buy'] != 0: #submit the order at or below target
						#format the orders
						p['buy'] = float(price_format%(p['buy'] - 0.01))
						p['target'] = float(price_format%p['target'])
						p.update({'stop_age':(60 * te.stop_age)})
						if float(te.wins / float(te.wins + te.loss + 0.000001)) > win_loss_gate_pct:
							#only submit an order if the win/loss ratio is greater than x%
							print "bid_maker: sending target buy order to server @ $" + str(p['buy'])
							server.put_target(json.dumps(p),pid)
							skip_sleep_delay = True #if target buy orders are active skip the sleep delay
						else:
							print "bid_maker: underperforming trade strategy, no order"
							p['buy'] = 0.00
							p['target'] = 0.00
							server.put_target(json.dumps(p),pid)
						print "-" * 40
						print "bid_maker: trigger criteria met, bid set."
						#print "\tQuartile     :",quartile
						print "\tBuy	    :$", p['buy']
						print "\tTarget	    :$",p['target']
						print "\tWin Ratio    :","%.3f"%((te.wins / float(te.wins + te.loss + 0.000001)) * 100),"%"
						print "-" * 40
					else:
						print "-" * 40
						print "bid_maker: trigger criteria not met, no bid set."
						print "\tBuy	    :$", p['buy']
						print "\tTarget	    :$",p['target']
						print "\tInput Target :$",target
						#print "\tMACD Log     : ",te.logs.get('macd')[-1][1]
						#print "\tMACD Trip    : ",te.macd_buy_trip
						print "-" * 40
						p.update({'stop_age':(60 * te.stop_age)}) #DEBUG ONLY!! - delete when done.
						p['buy'] = 0.00
						p['target'] = 0.00
						server.put_target(json.dumps(p),pid)


	while True:
		loop_time = time.time() - start_time
		if loop_time > 60:
			break
		time.sleep(60 - loop_time)
